#pragma once

#include <vex/iterable/range_base.h>
#include <vex/iterable/stl_interop.h>
#include <type_traits>
#include <utility>

namespace vex { namespace query {
    namespace detail {

        //template<class TRange> 
        //auto disambiguate(TRange&& p_range, std::true_type const &)
        //    -> decltype(std::forward<TRange>(p_range))
        //{
        //    return std::forward<TRange>(p_range);
        //}

        //template<class TContainer> 
        //auto disambiguate(TContainer&& p_container, std::false_type const &)
        //    -> decltype(::vex::iterable::make_range(std::forward<TContainer>(p_container)))
        //{
        //    return ::vex::iterable::make_range(std::forward<TContainer>(p_container));
        //}
    }

    template<class TRange> auto from(TRange&& p_input)
        -> typename iterable::lazy_enable_if_range<TRange, std::identity<TRange&&>>::type
    {
        return std::forward<TRange>(p_input);
    }

    template<class TContainer> auto from(TContainer& p_input)
        -> typename iterable::lazy_disable_if_range<TContainer,
        iterable::stl_interop::make_range_from_container<TContainer> >::type
    {
        return iterable::make_range(p_input);
    }

    template<class TContainer> auto from(TContainer const& p_input)
        -> typename iterable::lazy_disable_if_range<TContainer, 
        iterable::stl_interop::make_range_from_container<const TContainer> >::type
    {
        return iterable::make_range(p_input);
    }

    // though I like this approach much better, it completely turns out the intellisense with vs2012
    //template<class TInput> auto from(TInput&& p_input)
    //    -> decltype(detail::disambiguate(std::forward<TInput>(p_input), iterable::is_range<TInput>()))
    //{
    //    return ::vex::query::detail::disambiguate(
    //        std::forward<TInput>(p_input), iterable::is_range<TInput>());
    //}

    template<class TItr> auto from(TItr&& p_beg, TItr&& p_end)
        -> decltype(::vex::iterable::make_range(std::forward<TItr>(p_beg), std::forward<TItr>(p_end)))
    {
        return ::vex::iterable::make_range(std::forward<TItr>(p_beg), std::forward<TItr>(p_end));
    }
}}